home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Game Programming for Dummies (2nd Edition)
/
WinGamProgFD.iso
/
mac
/
DirectX SDK
/
DXSDK
/
samples
/
Multimedia
/
Direct3D
/
BumpMapping
/
BumpSelfShadow
/
bumpselfshadow.cpp
next >
Wrap
C/C++ Source or Header
|
2001-10-08
|
59KB
|
1,828 lines
//-----------------------------------------------------------------------------
// File: BumpSelfShadow.cpp
//
// Desc: Shows how to implement self-shadowing bump mapping
//
// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include <Windows.h>
#include <tchar.h>
#include <d3dx8.h>
#include "D3DApp.h"
#include "D3DFont.h"
#include "DXUtil.h"
//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
// A complex vertex, if we use vertex shaders we can handle this data ourselves
struct BiNormalVertex
{
FLOAT x,y,z;
FLOAT u,v;
FLOAT nx,ny,nz;
FLOAT bx,by,bz;
DWORD col;
INT RefCount;
};
struct ShaderVertex
{
FLOAT x,y,z;
FLOAT u,v;
FLOAT nx,ny,nz;
FLOAT bx,by,bz;
};
struct NormalVertex
{
FLOAT x,y,z;
FLOAT u,v;
FLOAT nx,ny,nz;
};
struct BasicVertex
{
FLOAT x,y,z;
DWORD col;
FLOAT u,v;
};
#define FVF_BASICVERTEX D3DFVF_XYZ|D3DFVF_DIFFUSE| D3DFVF_TEX1
//A BasicVertex FVF2
struct BasicVertex2
{
FLOAT x,y,z;
DWORD col;
FLOAT u,v;
FLOAT u1,v2;
};
#define FVF_BASICVERTEX2 D3DFVF_XYZ|D3DFVF_DIFFUSE| D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE2(1)
#define MAXTRIANGLES 4096
#define BASISMAPSIZE 32
#define RENDERTARGSIZE 256
struct sTriangle
{
WORD ind1,ind2,ind3;
};
class ShadowSet
{
sTriangle m_Triangles[MAXTRIANGLES];
LPDIRECT3DVERTEXBUFFER8 m_pScreenVB;
LPDIRECT3DVERTEXBUFFER8 m_pShad1;
LPDIRECT3DVERTEXBUFFER8 m_pVertices;
BiNormalVertex m_TriVertices[MAXTRIANGLES*3];
INT m_iNumTriangles,m_iNumVertices;
DWORD m_iHeightWidth,m_iHeightHeight;
IDirect3DDevice8 *m_pDev;
// our interleaved horizon maps with the precomputed basis textures
LPDIRECT3DTEXTURE8 m_pHorizonTextures[4];
LPDIRECT3DTEXTURE8 m_pBasisTextures[4];
// we render into this buffer and use it as a texture
LPDIRECT3DTEXTURE8 m_pRenderBuffer;
LPDIRECT3DTEXTURE8 m_pRenderBuffer2;
LPDIRECT3DTEXTURE8 m_pTempBuffer;
LPDIRECT3DSURFACE8 m_pOldRenderTarget;
LPDIRECT3DSURFACE8 m_pOldStencilZ;
LPDIRECT3DTEXTURE8 m_pNormalMap;
LPDIRECT3DTEXTURE8 m_pColorTexture;
LPDIRECT3DINDEXBUFFER8 m_pIndexBuffer;
D3DXMATRIX m_matObject;
D3DXMATRIX m_matView;
D3DXMATRIX m_matProj;
D3DXMATRIX m_matTot;
// our shaders
DWORD m_dwBasisShader;
DWORD m_dwShadowShader;
DWORD m_dwBumpShader;
DWORD m_dwPixShader;
TCHAR m_cColorName[160];
TCHAR m_cHeightName[160];
DWORD m_dwHeightLevels;
BOOL m_bInitalize;
BOOL m_bLoaded;
BOOL m_bUsePix;
// scratch space for loading/computing the textures
BYTE* m_pHeightMap[16];
BYTE* m_pHorizonMap[16];
BYTE* m_pBasisMap[16];
BYTE* m_pHorizonComp[4];
BYTE* m_pBasisComp[4];
// linear basis map
VOID BuildBasisMap(BYTE *pBasis,FLOAT PrimAngle,FLOAT Angle2);
BOOL BuildInterleavedMap(LPDIRECT3DTEXTURE8 &newTex, BYTE *r, BYTE *g, BYTE *b,
BYTE *a, INT width, INT height);
VOID BuildHorizonMap(BYTE *pHor, BYTE*, FLOAT dx, FLOAT dy, INT StepLength,
INT iWidth, INT iHeight, BOOL bWrapU, BOOL bWrapV);
public:
ShadowSet(TCHAR *HeightMapName, TCHAR *ColorTexName);
ShadowSet::~ShadowSet();
VOID ComputeLight(D3DXVECTOR3 &lightDir, D3DXMATRIX *pObject, D3DXMATRIX *pView, D3DXMATRIX *pProj);
VOID Render(BOOL,BOOL, BOOL, INT left, INT top, INT right, INT bottom);
VOID SetBuffers(LPDIRECT3DINDEXBUFFER8 pIndex, LPDIRECT3DVERTEXBUFFER8 pVertBuffer,
INT iNumFaces, INT iNumVertices);
HRESULT Init(IDirect3DDevice8*, BOOL bUsePix);
VOID DeleteDeviceObj();
VOID Restore();
VOID Invalidate();
};
//-----------------------------------------------------------------------------
// Name: class CMyD3DApplication
// Desc: Application class. The base class (CD3DApplication) provides the
// generic functionality needed in all Direct3D samples. CMyD3DApplication
// adds functionality specific to this sample program.
//-----------------------------------------------------------------------------
class CMyD3DApplication : public CD3DApplication
{
public:
CMyD3DApplication();
ShadowSet *m_pShadow;
D3DXMATRIX m_matObject;
D3DXMATRIX m_matView;
D3DXMATRIX m_matProj;
D3DXMATRIX m_matPosition;
D3DXVECTOR3 m_LightDir;
BOOL m_bLMouseDown;
BOOL m_bRMouseDown;
BOOL m_bFirstTime;
BOOL m_bRotate;
FLOAT m_xPos, m_yPos;
FLOAT m_oPosX, m_oPosY;
INT m_iIndex;
BYTE m_bKey[256];
FLOAT m_fSpeed;
FLOAT m_fAngularSpeed;
FLOAT m_fTheta;
FLOAT m_fTheta2;
BOOL m_bDebug;
BOOL m_bShadow;
BOOL m_bBump;
BOOL m_bUsePix;
D3DXVECTOR3 m_vecVelocity;
D3DXVECTOR3 m_vecAngularVelocity;
virtual HRESULT OneTimeSceneInit();
virtual HRESULT InitDeviceObjects();
virtual HRESULT RestoreDeviceObjects();
virtual HRESULT InvalidateDeviceObjects();
virtual HRESULT DeleteDeviceObjects();
virtual HRESULT FrameMove();
virtual HRESULT Render();
virtual LRESULT MsgProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
virtual HRESULT ConfirmDevice(D3DCAPS8*,DWORD,D3DFORMAT);
virtual HRESULT FinalCleanup();
private:
FLOAT m_fAspectRatio;
VOID CreateSphere();
VOID OnMouseMove();
VOID LoadXFile(TCHAR*);
CD3DFont* m_pFont;
CD3DFont* m_pFontSmall;
};
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point to the program. Initializes everything, and goes into a
// message-processing loop. Idle time is used to render the scene.
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
CMyD3DApplication d3dApp;
if( FAILED( d3dApp.Create( hInst ) ) )
return 0;
return d3dApp.Run();
}
//-----------------------------------------------------------------------------
// Name: ConfirmDevice()
// Desc: Called during device intialization, this code checks the device
// for some minimum set of capabilities
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
D3DFORMAT Format )
{
if( (dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
(dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) )
{
if( pCaps->VertexShaderVersion < D3DVS_VERSION(1,0) )
return E_FAIL;
}
if(!(pCaps->TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3))
return E_FAIL;
if(pCaps->MaxTextureBlendStages < 2)
return E_FAIL;
if( pCaps->PixelShaderVersion < D3DPS_VERSION(1,1) )
{
if( FAILED( m_pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal,
pCaps->DeviceType, Format, D3DUSAGE_RENDERTARGET,
D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8 ) ) )
{
return E_FAIL;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CMyD3DApplication()
// Desc: Application constructor. Sets attributes for the app.
//-----------------------------------------------------------------------------
CMyD3DApplication::CMyD3DApplication()
{
D3DXMATRIX matT;
m_fElapsedTime = 0.0f;
m_fAspectRatio = 0.0f;
m_dwCreationWidth = 400; // Width used to create window
m_dwCreationHeight = 400;
m_bUseDepthBuffer = TRUE;
m_bShowCursorWhenFullscreen = TRUE;
m_strWindowTitle = _T("Self-Shadow Bumpmap");
m_pShadow = NULL;
m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
m_pFontSmall = new CD3DFont( _T("Arial"), 9, D3DFONT_BOLD );
for(INT i=0; i<256; i++)
m_bKey[i] = FALSE;
m_bLMouseDown = FALSE;
m_bRMouseDown = FALSE;
m_bFirstTime = TRUE;
m_iIndex = 0;
m_bDebug = m_bShadow = m_bBump = TRUE;
m_fTheta = 0;
m_fTheta2 = 0;
D3DXMatrixIdentity(&m_matObject);
D3DXMatrixIdentity(&m_matView);
D3DXMatrixIdentity(&m_matPosition);
//initalize the camera and keyboard speeds
//this should probally change depending on the size
//of the object being viewed
m_fSpeed = 20.00f;
m_fAngularSpeed = 0.10f;
m_vecVelocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_vecAngularVelocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_LightDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
D3DXMatrixTranslation( &matT, 0,0, -40);
D3DXMatrixMultiply( &m_matPosition, &matT, &m_matPosition );
D3DXMatrixInverse( &m_matView, NULL, &m_matPosition );
}
HRESULT CMyD3DApplication::FinalCleanup()
{
SAFE_DELETE(m_pShadow);
return S_OK;
}
//track mouse movement
//just a crude interface to let the user move the object
VOID CMyD3DApplication::OnMouseMove()
{
RECT r;
FLOAT dx,dy;
D3DXMATRIX mat1,mat2,mat3;
GetWindowRect(m_hWnd,&r);
dx = ((FLOAT)m_xPos)/((FLOAT)r.right-r.left)*2 - 1;
dy = ((FLOAT)m_yPos)/((FLOAT)r.right-r.left)*2 - 1;
//right mouse button moves the light around
if(m_bRMouseDown)
{
m_LightDir.x = -dx;
m_LightDir.y = dy;
m_LightDir.z = .25f;
}
//left button rotates the object
if(m_bLMouseDown)
{
m_fTheta = -dy+m_oPosY;
m_fTheta2 = -dx+m_oPosX;
D3DXMatrixRotationX(&mat1,m_fTheta*.1f);
D3DXMatrixRotationY(&mat2,m_fTheta2*.1f);
D3DXMatrixMultiply(&mat3,&mat1,&mat2);
D3DXMatrixMultiply(&m_matObject,&m_matObject,&mat3);
}
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: Message proc function to handle key and menu input
//-----------------------------------------------------------------------------
LRESULT CMyD3DApplication::MsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT r;
D3DXMATRIX matT;
// Trap the context menu
if( WM_CONTEXTMENU==uMsg )
return 0;
switch(uMsg)
{
case WM_KEYUP:
//mark a key up
m_bKey[wParam] = FALSE;
break;
case WM_KEYDOWN:
//mark a key down
m_bKey[wParam] = TRUE;
//turn shadowing off
if(wParam == '2')
m_bShadow = !m_bShadow;
//turn bump mapping off
if(wParam == '3')
m_bBump = !m_bBump;
//auto rotate
if(wParam == '5')
m_bRotate = !m_bRotate;
//reset matrices
if(wParam == '4')
{
D3DXMatrixTranslation( &m_matPosition, 0,0, -40);
D3DXMatrixInverse( &m_matView, NULL, &m_matPosition );
D3DXMatrixIdentity(&m_matObject);
}
break;
//track left mouse button down
case WM_LBUTTONDOWN:
m_bLMouseDown=TRUE;
m_xPos = LOWORD(lParam);
m_yPos = HIWORD(lParam);
GetWindowRect(m_hWnd,&r);
m_oPosX = ((FLOAT)m_xPos)/((FLOAT)r.right-r.left)*2 - 1;
m_oPosY = ((FLOAT)m_yPos)/((FLOAT)r.right-r.left)*2 - 1;
break;
//track right mouse button
case WM_RBUTTONDOWN:
m_xPos = LOWORD(lParam);
m_yPos = HIWORD(lParam);
m_bRMouseDown = TRUE;
break;
//track mouse movement
case WM_MOUSEMOVE:
if(m_bRMouseDown || m_bLMouseDown)
{
m_xPos = LOWORD(lParam);
m_yPos = HIWORD(lParam);
}
OnMouseMove();
break;
case WM_RBUTTONUP:
m_bRMouseDown=FALSE;
break;
case WM_LBUTTONUP:
m_bLMouseDown=FALSE;
break;
}
return CD3DApplication::MsgProc( hwnd, uMsg, wParam, lParam );
}
//load an X file
VOID CMyD3DApplication::LoadXFile(TCHAR* name)
{
LPD3DXMESH pMeshSysMem=NULL,pMeshSysMem2=NULL;
LPDIRECT3DINDEXBUFFER8 pIndexBuffer=NULL;
HRESULT hr;
DWORD dwFaces,dwVertices;
LPDIRECT3DVERTEXBUFFER8 pVertexBuffer = NULL;
hr = D3DXLoadMeshFromX(name, D3DXMESH_SYSTEMMEM,
m_pd3dDevice, NULL, NULL, NULL, &pMeshSysMem);
if(FAILED(hr))
goto FAIL;
//reform the mesh to one which will have space for the tangent vectors
hr = pMeshSysMem->CloneMeshFVF(D3DXMESH_MANAGED, D3DFVF_NORMAL
| D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_XYZ,
m_pd3dDevice, &pMeshSysMem2);
//compute the normals
hr = D3DXComputeNormals(pMeshSysMem,NULL);
if(FAILED(hr))
goto FAIL;
//compute the tangent vectors in the texture space and load them into
//the 1'rd texture stage (which is 3d), read the texture coords from the 0th texture
//stage. Don't need the V direction vector since it is assumed to be U x N.
hr = D3DXComputeTangent(pMeshSysMem,0,pMeshSysMem2,1,D3DX_COMP_TANGENT_NONE,TRUE,NULL);
if(FAILED(hr))
goto FAIL;
SAFE_RELEASE(pMeshSysMem);
hr = pMeshSysMem2->GetIndexBuffer(&pIndexBuffer);
if(FAILED(hr))
goto FAIL;
hr = pMeshSysMem2->GetVertexBuffer(&pVertexBuffer);
if(FAILED(hr))
goto FAIL;
dwFaces = pMeshSysMem2->GetNumFaces();
dwVertices = pMeshSysMem2->GetNumVertices();
//give them to the shadow object
m_pShadow->SetBuffers(pIndexBuffer,pVertexBuffer,dwFaces,dwVertices);
SAFE_RELEASE(pVertexBuffer)
SAFE_RELEASE(pIndexBuffer)
//cleanup
FAIL:
SAFE_RELEASE(pMeshSysMem)
SAFE_RELEASE(pMeshSysMem2)
SAFE_RELEASE(pVertexBuffer)
SAFE_RELEASE(pIndexBuffer)
}
//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Animates the scene
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::FrameMove()
{
D3DXMATRIX matWorld,mat1,mat2;
// Update world matrix
// Process keyboard input
D3DXVECTOR3 vecT(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vecR(0.0f, 0.0f, 0.0f);
vecT = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
if(m_bKey['W']) vecT.z += 2.0f; // Move Forward
if(m_bKey['S']) vecT.z -= 2.0f; // Move Backward
m_vecVelocity = m_vecVelocity * 0.9f - vecT * 0.1f;
m_vecAngularVelocity = m_vecAngularVelocity * 0.9f - vecR * 0.1f;
// Update position and view matricies
D3DXMATRIX matT, matR;
D3DXQUATERNION qR;
vecT = m_vecVelocity * m_fElapsedTime * m_fSpeed;
vecR = m_vecAngularVelocity * m_fElapsedTime * m_fAngularSpeed;
D3DXMatrixTranslation( &matT, -vecT.x, -vecT.y, -vecT.z );
D3DXMatrixMultiply( &m_matPosition, &matT, &m_matPosition );
D3DXQuaternionRotationYawPitchRoll( &qR, vecR.y, vecR.x, vecR.z );
D3DXMatrixRotationQuaternion( &matR, &qR );
D3DXMatrixMultiply( &m_matPosition, &matR, &m_matPosition );
D3DXMatrixInverse( &m_matView, NULL, &m_matPosition );
//apply rotation
if(m_bRotate)
{
D3DXMatrixRotationY(&matR, -m_fElapsedTime*.5f);
D3DXMatrixMultiply(&m_matObject,&matR,&m_matObject);
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Renders the scene.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::Render()
{
HRESULT hr;
FLOAT fAspectRatio = (FLOAT)m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
// Update projection matrix
if(m_fAspectRatio != fAspectRatio)
{
D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&m_matProj, 0.05f, fAspectRatio, 1.0f, 10000.0f);
m_fAspectRatio = fAspectRatio;
}
m_pShadow->ComputeLight(m_LightDir,&m_matObject,&m_matView,&m_matProj);
if(FAILED(hr = m_pd3dDevice->BeginScene()))
return hr;
if(m_bWindowed)
{
m_pShadow->Render(m_bDebug, m_bShadow, m_bBump, m_rcWindowClient.left,
m_rcWindowClient.top, m_rcWindowClient.right - m_rcWindowClient.left,
m_rcWindowClient.bottom - m_rcWindowClient.top);
}
else
{
m_pShadow->Render(m_bDebug, m_bShadow, m_bBump, 0, 0,
m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height);
}
// Output statistics
m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
m_pFontSmall->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), TEXT("2: Toggle shadow") );
m_pFontSmall->DrawText( 2, 60, D3DCOLOR_ARGB(255,255,255,255), TEXT("3: Toggle bumpmapping") );
m_pFontSmall->DrawText( 2, 80, D3DCOLOR_ARGB(255,255,255,255), TEXT("4: Reset object") );
m_pFontSmall->DrawText( 2,100, D3DCOLOR_ARGB(255,255,255,255), TEXT("5: Toggle spin") );
if(FAILED(hr = m_pd3dDevice->EndScene()))
return hr;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: OneTimeSceneInit()
// Desc: Called during initial app startup, this function performs all the
// permanent initialization.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::OneTimeSceneInit()
{
// Set cursor to indicate that user can move the object with the mouse
#ifdef _WIN64
SetClassLongPtr( m_hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor( NULL, IDC_SIZEALL ) );
#else
SetClassLong( m_hWnd, GCL_HCURSOR, (LONG)LoadCursor( NULL, IDC_SIZEALL ) );
#endif
TCHAR strBump[160], strColor[160];
DXUtil_FindMediaFile(strBump, _T("earthbump.bmp"));
DXUtil_FindMediaFile(strColor,_T("earth.bmp"));
m_pShadow = new ShadowSet(strBump, strColor);
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InitDeviceObjects()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::InitDeviceObjects()
{
D3DXMATRIX matT;
m_pFont->InitDeviceObjects( m_pd3dDevice );
m_pFontSmall->InitDeviceObjects( m_pd3dDevice );
D3DXMatrixIdentity(&m_matObject);
D3DXMatrixIdentity(&m_matView);
D3DXMatrixIdentity(&m_matPosition);
m_fSpeed = 20.0f;
m_fAngularSpeed = .10f;
m_vecVelocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_vecAngularVelocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_LightDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
D3DXMatrixTranslation( &matT, 0,0, -40);
D3DXMatrixMultiply( &m_matPosition, &matT, &m_matPosition );
D3DXMatrixInverse( &m_matView, NULL, &m_matPosition );
D3DCAPS8 Caps;
m_pd3dDevice->GetDeviceCaps(&Caps);
//detect if the hardware supports pixel shaders
//if it does, then the shadow term can be done in one pass,
//resulting in much faster and better results
if(Caps.PixelShaderVersion < D3DPS_VERSION(1,1) )
m_bUsePix = FALSE;
else
m_bUsePix = TRUE;
if(FAILED( m_pShadow->Init(m_pd3dDevice, m_bUsePix)))
return E_FAIL;
TCHAR strFile[160];
DXUtil_FindMediaFile(strFile, _T("sphere.x"));
LoadXFile(strFile);
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: RestoreDeviceObjects()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::RestoreDeviceObjects()
{
m_pFont->RestoreDeviceObjects();
m_pFontSmall->RestoreDeviceObjects();
m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pShadow->Restore();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InvalidateDeviceObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::InvalidateDeviceObjects()
{
m_pFont->InvalidateDeviceObjects();
m_pFontSmall->InvalidateDeviceObjects();
m_pShadow->Invalidate();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Called when the app is exiting, or the device is being changed,
// this function deletes any device dependent objects.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::DeleteDeviceObjects()
{
m_pFont->DeleteDeviceObjects();
m_pFontSmall->DeleteDeviceObjects();
m_pShadow->DeleteDeviceObj();
return S_OK;
}
ShadowSet::ShadowSet(TCHAR *name,TCHAR *colorName)
{
DWORD i,x,y;
FLOAT fRange = D3DX_PI/4;
m_bInitalize = FALSE;
m_bLoaded = FALSE;
DWORD dwIndex =0;
m_pOldStencilZ=NULL;
//set everything to NULL
for(i = 0;i < 16;i++)
{
m_pBasisMap[i] = NULL;
m_pHorizonMap[i] = NULL;
m_pHeightMap[i] = NULL;
if(i<4)
{
m_pBasisTextures[i] = NULL;
m_pHorizonTextures[i] = NULL;
}
}
m_pRenderBuffer = NULL;
m_pRenderBuffer2 = NULL;
m_pNormalMap = NULL;
m_pColorTexture = NULL;
if(colorName)
_tcscpy(m_cColorName,colorName);
else
m_cColorName[0] = 0;
if(name)
_tcscpy(m_cHeightName,name);
else
m_cColorName[0] = 0;
//Load Bitmap
RGBQUAD rgbq[256];
BITMAP bp;
BYTE *bits;
BYTE *tb;
HBITMAP texmap;
HDC tDC;
BYTE *temploc,*srcloc;
texmap = (HBITMAP)LoadImage(NULL, name, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if(texmap==0)
goto FAIL;
GetObject(texmap, sizeof(BITMAP), (LPSTR) &bp);
m_iHeightWidth = bp.bmWidth;
m_iHeightHeight = bp.bmHeight;
//XXX - need to check for powers of 2
tDC = CreateCompatibleDC(NULL);
SelectObject(tDC, texmap);
GetObject(tDC, sizeof(BITMAP), (LPSTR) &bp);
bits = (BYTE *)bp.bmBits;
GetDIBColorTable(tDC,0,256,rgbq);
tb = m_pHeightMap[0] = new BYTE[m_iHeightWidth*m_iHeightHeight];
if(tb==NULL)
goto FAIL;
if(bp.bmBitsPixel == 8)
{
for(y = 0; y < m_iHeightHeight; y++)
{
for(x = 0; x < m_iHeightWidth ; x++)
{
temploc = &tb[(y * (m_iHeightWidth) + x) ];
srcloc = &bits[(m_iHeightHeight-y-1) * (bp.bmWidthBytes) + x];
temploc[0] = rgbq[*srcloc].rgbRed;
}
}
}
else
{
for(y = 0; y < m_iHeightHeight; y++)
{
for(x = 0; x < m_iHeightWidth ; x++)
{
temploc = &tb[(y * (m_iHeightWidth) + x)];
srcloc = &bits[(m_iHeightHeight-y-1) * (bp.bmWidthBytes) + x*3];
temploc[0] = srcloc[2];
}
}
}
DeleteObject(texmap);
DeleteDC(tDC);
DWORD curHeight,curWidth;
curHeight = m_iHeightHeight;
curWidth = m_iHeightWidth;
curHeight = curHeight >> 1;
curWidth = curWidth >> 1;
/* for(i = 1;(curHeight > 2) && (curWidth > 2);i++)
{
m_pHeightMap[i] = new BYTE[curHeight*curWidth];
if(!m_pHeightMap)
goto FAIL;
//do an average of the four neighboring pixels of the previous level
for(y = 0;y < curHeight;y++)
{
pLine = &m_pHeightMap[i-1][y*2*(2*curWidth)];
for(x = 0; x < curWidth;x++)
{
m_pHeightMap[i][y*curWidth+x] = (pLine[0] + pLine[1] +
pLine[2*curWidth]+pLine[2*curWidth+1])/4;
pLine+=2;
}
}
curHeight = curHeight >> 1;
curWidth = curWidth >> 1;
}
m_dwHeightLevels = i;
*/
//now set up the basis maps
for(i = 0;i < 8;i++)
{
m_pBasisMap[i] = new BYTE[BASISMAPSIZE*BASISMAPSIZE];
m_pHorizonMap[i] = new BYTE[m_iHeightWidth*m_iHeightHeight];
if(m_pBasisMap[i] == NULL ||
m_pHorizonMap[i] == NULL)
goto FAIL;
BuildBasisMap(m_pBasisMap[i],((FLOAT)(D3DX_PI*i))/4.0f,fRange);
BuildHorizonMap(m_pHorizonMap[i],m_pHeightMap[0],cosf((FLOAT)(D3DX_PI*i)/4.0f), sinf((FLOAT)(D3DX_PI*i)/4.0f),15,m_iHeightWidth,
m_iHeightHeight,TRUE,TRUE);
}
m_pShad1 = NULL;
m_pRenderBuffer = NULL;
m_pIndexBuffer = NULL;
m_pScreenVB=NULL;
m_iNumTriangles = 0;
m_iNumVertices = 0;
m_pVertices = NULL;
m_bLoaded = TRUE;
return;
FAIL:
return;
}
ShadowSet::~ShadowSet()
{
INT i;
for(i = 0;i < 16;i++)
{
if(m_pBasisMap[i])
delete []m_pBasisMap[i];
if(m_pHorizonMap[i])
delete []m_pHorizonMap[i];
if(m_pHeightMap[i])
delete []m_pHeightMap[i];
}
}
HRESULT ShadowSet::Init(IDirect3DDevice8 *pDev, BOOL bUsePix)
{
HRESULT hr;
LPD3DXBUFFER pCode=NULL;
INT iWidth,iHeight;
m_pDev = pDev;
LPDIRECT3DTEXTURE8 pHeightMap;
D3DSURFACE_DESC desc;
DWORD dwDecl[] =
{
D3DVSD_STREAM(0),
D3DVSD_REG(0, D3DVSDT_FLOAT3),
D3DVSD_REG(3, D3DVSDT_FLOAT3),
D3DVSD_REG(7, D3DVSDT_FLOAT2),
D3DVSD_REG(8, D3DVSDT_FLOAT3),
D3DVSD_END()
};
TCHAR Shad1[255],Shad2[255],Shad3[255];
m_bUsePix = bUsePix;
if(!m_bLoaded)
goto FAIL;
if(FAILED(hr = D3DXCreateTextureFromFile(m_pDev,m_cColorName,&m_pColorTexture)))
goto FAIL;
if(FAILED(hr = D3DXCreateTextureFromFile(m_pDev,m_cHeightName,&pHeightMap)))
goto FAIL;
pHeightMap->GetLevelDesc(0,&desc);
iWidth = desc.Width;
iHeight = desc.Height;
if(FAILED(hr = D3DXCreateTexture(m_pDev,iWidth,iHeight,0,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED, &m_pNormalMap)))
goto FAIL;
D3DXComputeNormalMap(m_pNormalMap,pHeightMap,NULL,0,D3DX_CHANNEL_RED,10);
pHeightMap->Release();
//two methods
if(!m_bUsePix)
{
//don't have a dp4, so need to put the maps into 3 basis texture and 3 horizon maps
//basis maps are not-content specific - they are just LERP tables
//build the interleave maps
if(!BuildInterleavedMap(m_pBasisTextures[0],m_pBasisMap[0],m_pBasisMap[1],m_pBasisMap[2],NULL,BASISMAPSIZE,BASISMAPSIZE))
goto FAIL;
if(!BuildInterleavedMap(m_pBasisTextures[1],m_pBasisMap[3],m_pBasisMap[4],m_pBasisMap[5],NULL,BASISMAPSIZE,BASISMAPSIZE))
goto FAIL;
if(!BuildInterleavedMap(m_pBasisTextures[2],m_pBasisMap[6],m_pBasisMap[7],NULL,NULL,BASISMAPSIZE,BASISMAPSIZE))
goto FAIL;
if(!BuildInterleavedMap(m_pHorizonTextures[0],m_pHorizonMap[0],m_pHorizonMap[1],m_pHorizonMap[2],NULL,m_iHeightWidth,m_iHeightHeight))
goto FAIL;
if(!BuildInterleavedMap(m_pHorizonTextures[1],m_pHorizonMap[3],m_pHorizonMap[4],m_pHorizonMap[5],NULL,m_iHeightWidth,m_iHeightHeight))
goto FAIL;
if(!BuildInterleavedMap(m_pHorizonTextures[2],m_pHorizonMap[6],m_pHorizonMap[7],NULL,NULL,m_iHeightWidth,m_iHeightHeight))
goto FAIL;
if(FAILED(hr = D3DXFilterTexture(m_pHorizonTextures[0],NULL,0,D3DX_FILTER_BOX)))
goto FAIL;
if(FAILED(hr = D3DXFilterTexture(m_pHorizonTextures[1],NULL,0,D3DX_FILTER_BOX)))
goto FAIL;
if(FAILED(hr = D3DXFilterTexture(m_pHorizonTextures[2],NULL,0,D3DX_FILTER_BOX)))
goto FAIL;
DXUtil_FindMediaFile(Shad1,_T("bumpshader.vsh"));
DXUtil_FindMediaFile(Shad2,_T("bumpshader2.vsh"));
DXUtil_FindMediaFile(Shad3,_T("bumpshader3.vsh"));
if( FAILED( hr = D3DXAssembleShaderFromFile(Shad2, 0, NULL, &pCode, NULL ) ) )
goto FAIL;
if( FAILED( hr = m_pDev->CreateVertexShader( dwDecl,(DWORD*)pCode->GetBufferPointer(), &m_dwBasisShader, 0 ) ) )
goto FAIL;
SAFE_RELEASE(pCode);
if( FAILED( hr = D3DXAssembleShaderFromFile(Shad1, 0, NULL, &pCode, NULL ) ) )
goto FAIL;
if( FAILED( hr = m_pDev->CreateVertexShader( dwDecl,(DWORD*)pCode->GetBufferPointer(), &m_dwShadowShader, 0 ) ) )
goto FAIL;
SAFE_RELEASE(pCode);
if( FAILED( hr = D3DXAssembleShaderFromFile(Shad3, 0, NULL, &pCode, NULL ) ) )
goto FAIL;
if( FAILED(hr = m_pDev->CreateVertexShader( dwDecl,(DWORD*)pCode->GetBufferPointer(), &m_dwBumpShader, 0 ) ) )
goto FAIL;
SAFE_RELEASE(pCode);
//create render targets for pic-shader emulation
if(FAILED(hr = m_pDev->CreateTexture(RENDERTARGSIZE,RENDERTARGSIZE,0,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pRenderBuffer)))
goto FAIL;
if(FAILED(hr = m_pDev->CreateTexture(RENDERTARGSIZE,RENDERTARGSIZE,0,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pRenderBuffer2)))
goto FAIL;
}
else
{
//build the interleave maps, use the Alpha to
//basis maps are not-content specific - they are just LERP tables
if(!BuildInterleavedMap(m_pBasisTextures[0],m_pBasisMap[0],m_pBasisMap[1],m_pBasisMap[2],m_pBasisMap[3],BASISMAPSIZE,BASISMAPSIZE))
goto FAIL;
if(!BuildInterleavedMap(m_pBasisTextures[1],m_pBasisMap[4],m_pBasisMap[5],m_pBasisMap[6],m_pBasisMap[7],BASISMAPSIZE,BASISMAPSIZE))
goto FAIL;
if(!BuildInterleavedMap(m_pHorizonTextures[0],m_pHorizonMap[0],m_pHorizonMap[1],m_pHorizonMap[2],m_pHorizonMap[3],m_iHeightWidth,m_iHeightHeight))
goto FAIL;
if(!BuildInterleavedMap(m_pHorizonTextures[1],m_pHorizonMap[4],m_pHorizonMap[5],m_pHorizonMap[6],m_pHorizonMap[7],m_iHeightWidth,m_iHeightHeight))
goto FAIL;
if(FAILED(hr = D3DXFilterTexture(m_pHorizonTextures[0],NULL,0,D3DX_FILTER_BOX)))
goto FAIL;
if(FAILED(hr = D3DXFilterTexture(m_pHorizonTextures[1],NULL,0,D3DX_FILTER_BOX)))
goto FAIL;
//load the required shaders
DXUtil_FindMediaFile(Shad1,_T("bumpshader4.vsh"));
DXUtil_FindMediaFile(Shad2,_T("shadowbumpshader.psh"));
DXUtil_FindMediaFile(Shad3,_T("bumpshader3.vsh"));
if(FAILED(hr = D3DXAssembleShaderFromFile(Shad1,0,NULL, &pCode,NULL) ) )
goto FAIL;
if( FAILED( hr = m_pDev->CreateVertexShader( dwDecl,(DWORD*)pCode->GetBufferPointer(), &m_dwShadowShader, 0 ) ) )
goto FAIL;
SAFE_RELEASE(pCode);
if(FAILED(hr = D3DXAssembleShaderFromFile(Shad2,0,NULL, &pCode,NULL) ) )
goto FAIL;
if( FAILED( hr = m_pDev->CreatePixelShader((DWORD*)pCode->GetBufferPointer(), &m_dwPixShader) ) )
goto FAIL;
SAFE_RELEASE(pCode);
if( FAILED( hr = D3DXAssembleShaderFromFile(Shad3, 0, NULL, &pCode, NULL ) ) )
goto FAIL;
if( FAILED(hr = m_pDev->CreateVertexShader( dwDecl,(DWORD*)pCode->GetBufferPointer(), &m_dwBumpShader, 0 ) ) )
goto FAIL;
SAFE_RELEASE(pCode);
}
m_bInitalize = TRUE;
return S_OK;
FAIL:
SAFE_RELEASE(pCode);
return E_FAIL;
}
VOID ShadowSet::DeleteDeviceObj()
{
for(INT i=0;i<4;i++)
{
SAFE_RELEASE(m_pHorizonTextures[i]);
SAFE_RELEASE(m_pBasisTextures[i]);
}
SAFE_RELEASE(m_pNormalMap);
SAFE_RELEASE(m_pColorTexture);
SAFE_RELEASE(m_pRenderBuffer);
SAFE_RELEASE(m_pRenderBuffer2);
SAFE_RELEASE(m_pIndexBuffer);
SAFE_RELEASE(m_pVertices);
SAFE_RELEASE(m_pScreenVB);
SAFE_RELEASE(m_pShad1);
if(m_pDev)
{
if(!m_bUsePix)
{
m_pDev->DeleteVertexShader(m_dwBumpShader);
m_pDev->DeleteVertexShader(m_dwShadowShader);
m_pDev->DeleteVertexShader(m_dwBasisShader);
}
else
{
m_pDev->DeleteVertexShader(m_dwShadowShader);
m_pDev->DeletePixelShader(m_dwPixShader);
}
}
}
VOID ShadowSet::Restore()
{
HRESULT hr;
SAFE_RELEASE(m_pRenderBuffer);
SAFE_RELEASE(m_pRenderBuffer2);
if(!m_bUsePix)
{
hr = m_pDev->CreateTexture(RENDERTARGSIZE, RENDERTARGSIZE, 0,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pRenderBuffer);
hr = m_pDev->CreateTexture(RENDERTARGSIZE, RENDERTARGSIZE, 0,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pRenderBuffer2);
}
m_pDev->GetRenderTarget(&m_pOldRenderTarget);
hr = m_pDev->GetDepthStencilSurface(&m_pOldStencilZ);
}
VOID ShadowSet::Invalidate()
{
SAFE_RELEASE(m_pRenderBuffer);
SAFE_RELEASE(m_pRenderBuffer2);
SAFE_RELEASE(m_pOldRenderTarget);
SAFE_RELEASE(m_pOldStencilZ);
}
// this builds a basis map
// the basis maps will be interleaved, or we will pack 3 of them into one texture
// (we could pack 4, but we can't use the alpha channel in our dot multiplies)
// but we will assume that the u,v represent the angle with respect to the center of the
// of the texture (.5,.5), So if we want the basis function for the light vector
// (1,.5) we'd look at the point (1,.75)
VOID ShadowSet::BuildBasisMap(BYTE *pBasis,FLOAT PrimAngle,FLOAT fAngle2)
{
INT x,y;
FLOAT fEndX,fEndY,fAngle,fPercent;
FLOAT u,v,dot,nx,ny,fsq;
BYTE *pCurLine;
u = cosf(PrimAngle);
v = sinf(PrimAngle);
for(y = 0;y < BASISMAPSIZE;y++)
{
pCurLine = &pBasis[y*BASISMAPSIZE];
for(x = 0;x < BASISMAPSIZE;x++)
{
fEndX = x - .5f*BASISMAPSIZE;
fEndY = y - .5f*BASISMAPSIZE;
//take the dot product of the normalized vectors
fsq = sqrtf(fEndX*fEndX+fEndY*fEndY);
if(fsq == 0)
{
fPercent = 128;
}
else
{
// we remember our definiton of dot product,
// cos(Angle) = DotProduct of Normalzed vectors
// so Angle = acos(DotProduct)
nx = fEndX/fsq;
ny = fEndY/fsq;
dot = nx*u + ny*v;
fAngle = acosf(dot);
if(fabs(fAngle) < fAngle2)
{
fPercent = 128 + fabsf(fAngle-fAngle2)*127/fAngle2;
if(fPercent>255)
fPercent=255;
}
else
{
fPercent = 128;
}
}
*pCurLine = (BYTE)fPercent;
pCurLine++;
}
}
}
BOOL ShadowSet::BuildInterleavedMap(LPDIRECT3DTEXTURE8 &newTex,
BYTE *r,
BYTE *g,
BYTE *b,
BYTE *a,INT width,INT height)
{
HRESULT hr;
LPDIRECT3DTEXTURE8 pTexture;
D3DLOCKED_RECT LockedRect;
BYTE *pBase,*pLine;
INT x,y;
hr = D3DXCreateTexture(m_pDev, width, height, 0, 0,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture);
if(hr != S_OK)
return(FALSE);
hr = pTexture->LockRect(0,&LockedRect,NULL,0);
if(hr != S_OK)
{
pTexture->Release();
return(FALSE);
}
pBase = (BYTE *)LockedRect.pBits;
for(y = 0;y < height;y++)
{
pLine = &pBase[y*LockedRect.Pitch];
for(x = 0;x < width;x++)
{
if(r)
pLine[2] = r[y*width + x];
else
pLine[2] = 128;
if(g)
pLine[1] = g[y*width + x];
else
pLine[1] = 128;
if(b)
pLine[0] = b[y*width + x];
else
pLine[0] = 128;
if(a)
pLine[3] = a[y*width + x];
else
pLine[3] = 128;
pLine+=4;
}
}
pTexture->UnlockRect(0);
newTex = pTexture;
return TRUE;
}
#define MAPHEIGHT .175f
#define MAPHEIGHT2 .175f
VOID ShadowSet::BuildHorizonMap(BYTE *pHor,BYTE* pHeight,FLOAT dx,FLOAT dy,INT iStepLength,
INT iWidth,INT iHeight,BOOL bWrapU,BOOL bWrapV)
{
INT x,y;
INT imx,imy,i;
FLOAT fpx,fpy;
BYTE *pCurHurLine;
FLOAT fMaxAngle,fNewAngle,fDeltaX,fDeltaY,fHeight;
for(y = 0;y < iHeight;y++)
{
pCurHurLine = &pHor[y*iWidth];
for(x = 0;x < iWidth;x ++)
{
//we assume its completly visible at zero
fMaxAngle = 0;
fpx = (FLOAT)x;
fpy = (FLOAT)y;
for(i = 0;i < iStepLength;i++)
{
fpx += dx;
fpy += dy;
imx = (INT) fpx;
imy = (INT) fpy;
//don't check against ourselves for blocking
if(imx == x && imy == y)
continue;
//if we are out of bounds, we're done
//if the texture is repeating - this should
//probally wrap
if(imx < 0)
{
if(bWrapU)
imx = iWidth-1;
else continue;
}
if(imx >= iWidth)
{
if(bWrapU)
imx = 0;
else continue;
}
if(imy < 0)
{
if(bWrapV)
imy = iHeight-1;
else continue;
}
if(imy >= iHeight)
{
if(bWrapV)
imy = 0;
else continue;
}
fDeltaX = fpx - x;
fDeltaY = fpy - y;
fHeight = pHeight[imy*iWidth+imx]*MAPHEIGHT-pHeight[y*iWidth+x]*MAPHEIGHT;
//this is the dot prodoct
//Since we are dotting against the normal, (0,0,1) this is just
// the Height normalized, or the Height over the length of the vector
fNewAngle = fHeight/sqrtf(fDeltaX*fDeltaX + fDeltaY*fDeltaY + fHeight*fHeight);
//if we found a further obstruction, use it
if(fNewAngle > fMaxAngle)
fMaxAngle = fNewAngle;
}
//centered around 128
*pCurHurLine = 128 + (BYTE) ((FLOAT)fMaxAngle*127);
pCurHurLine++;
}
}
}
VOID ShadowSet::ComputeLight(D3DXVECTOR3 &lightDir,
D3DXMATRIX *pObject, D3DXMATRIX *pView, D3DXMATRIX *pProj)
{
D3DXVECTOR3 U,V,W,Pos;
D3DXVECTOR4 light,one(1,1,1,1),half(0.5f,0.5f,.5f,.5f);//.5f);
if(!m_bInitalize)
return;
light.x = lightDir.x;
light.y = lightDir.y;
light.z = lightDir.z;
light.w = 0;
D3DXVec4Normalize(&light,&light);
m_matObject = *pObject;
m_matView = *pView;
m_matProj = *pProj;
D3DXMATRIX temp;
D3DXMatrixMultiply(&m_matTot, pObject, pView);
D3DXMatrixTranspose(&temp, &m_matTot);
//the inverse transform
m_pDev->SetVertexShaderConstant( 16,pObject, 4);
D3DXMatrixMultiply(&m_matTot,&m_matTot,pProj);
D3DXMatrixTranspose(&m_matTot,&m_matTot);
D3DXMatrixTranspose(&m_matObject,pObject);
//load the values into the registers
m_pDev->SetVertexShaderConstant( 12, &light, 1 );
m_pDev->SetVertexShaderConstant( 32, &one, 1);
m_pDev->SetVertexShaderConstant( 33, &half, 1);
m_pDev->SetVertexShaderConstant( 0, &m_matObject, 4);
m_pDev->SetVertexShaderConstant( 8,&m_matTot, 4);
}
VOID ShadowSet::Render(BOOL bShow, BOOL bShad, BOOL bBump, INT iLeft, INT iTop,
INT iRight, INT iBottom)
{
if(!m_pVertices || !m_pIndexBuffer || !m_pDev)
return;
HRESULT hr;
INT i;
VOID* pVerts;
LPDIRECT3DSURFACE8 pSurface;
D3DVIEWPORT8 ViewPort,OldPort;
if(!m_bInitalize)
return;
static struct { FLOAT x,y,z,w, u1,v1;} s_Verts2[] =
{
{ RENDERTARGSIZE, 0.0f, 0.0f, 1.0f, 1,0,},
{ RENDERTARGSIZE, RENDERTARGSIZE, 0.0f, 1.0f, 1,1,},
{ 0.0f, 0.0f, 0.0f, 1.0f, 0,0,},
{ 0.0f, RENDERTARGSIZE, 0.0f, 1.0f, 0,1,}
};
static struct { FLOAT x,y,z,w; DWORD color;} s_Verts3[] =
{
{750.0f, 0.0f, 0.0f,0, D3DCOLOR_ARGB( 0xa0,0xff, 0x00, 0x00 ),},
{750.0f, 375.0f, 0.0f,0, D3DCOLOR_ARGB( 0xa0,0xff,00, 0x00),},
{ 0.0f, 0.0f, 0.0f, 0, D3DCOLOR_ARGB( 0xa0,0xff,0x00, 0x00),},
{ 0.0f, 375.0f, 0.0f,0, D3DCOLOR_ARGB( 0xa0,0xff, 0x00, 0x00),},
};
m_pDev->SetIndices(m_pIndexBuffer,0);
if(!m_bUsePix)
{
//sets up polygons that
//are the same size as the screen
//(well... almost)
OldPort.X = iLeft;
OldPort.Y = iTop;
OldPort.Width = iRight-iLeft;
OldPort.Height = iBottom-iTop;
OldPort.MaxZ = 1;
OldPort.MinZ = 0;
s_Verts2[0].x = (FLOAT) OldPort.Width;
s_Verts2[1].x = (FLOAT)OldPort.Width;
s_Verts2[1].y =(FLOAT) OldPort.Height;
s_Verts2[3].y = (FLOAT)OldPort.Height;
s_Verts3[0].x = (FLOAT)OldPort.Width;
s_Verts3[1].x = (FLOAT)OldPort.Width;
s_Verts3[1].y = (FLOAT)OldPort.Height;
s_Verts3[3].y =(FLOAT) OldPort.Height;
if(!bShow)
{
s_Verts3[0].color = D3DCOLOR_ARGB( 0xa0,0x00, 0x00, 0x00 );
s_Verts3[1].color = D3DCOLOR_ARGB( 0xa0,0x00, 0x00, 0x00 );
s_Verts3[2].color = D3DCOLOR_ARGB( 0xa0,0x00, 0x00, 0x00 );
s_Verts3[3].color = D3DCOLOR_ARGB( 0xa0,0x00, 0x00, 0x00 );
}
else
{
s_Verts3[0].color = D3DCOLOR_ARGB( 0x70,0xff, 0x00, 0x00 );
s_Verts3[1].color = D3DCOLOR_ARGB( 0x70,0xff, 0x00, 0x00 );
s_Verts3[2].color = D3DCOLOR_ARGB( 0x70,0xff, 0x00, 0x00 );
s_Verts3[3].color = D3DCOLOR_ARGB( 0x70,0xff, 0x00, 0x00 );
}
//fill the VBs
if(m_pShad1==NULL)
{
if ( FAILED( hr = m_pDev->CreateVertexBuffer( sizeof(s_Verts2),
0x0, D3DFVF_XYZRHW | D3DFVF_TEX1, D3DPOOL_SYSTEMMEM, &m_pShad1 ) ) )
{
goto Fail;
}
}
if ( FAILED(hr = m_pShad1->Lock( 0, sizeof(s_Verts2), (BYTE **)(&pVerts), 0 )) )
goto Fail;
memcpy( (VOID*)pVerts, (VOID*)s_Verts2, sizeof(s_Verts2) );
if (FAILED(hr = m_pShad1->Unlock()) )
goto Fail;
if(m_pScreenVB==NULL)
{
if ( FAILED( hr = m_pDev->CreateVertexBuffer( sizeof(s_Verts3),
0x0, D3DFVF_XYZRHW | D3DFVF_DIFFUSE, D3DPOOL_SYSTEMMEM, &m_pScreenVB) ) )
{
goto Fail;
}
}
if ( FAILED(hr = m_pScreenVB->Lock( 0, sizeof(s_Verts3), (BYTE **)(&pVerts), 0 )) )
goto Fail;
memcpy( (VOID*)pVerts, (VOID*)s_Verts3, sizeof(s_Verts3) );
if (FAILED(hr = m_pScreenVB->Unlock()) )
goto Fail;
m_pDev->SetRenderState(D3DRS_ZENABLE,FALSE);
if(bShad)
{
//first set the Rendertarget
hr = m_pRenderBuffer->GetSurfaceLevel(0,&pSurface);
hr = m_pDev->SetRenderTarget(pSurface,NULL);
ViewPort.X = 0;
ViewPort.Y = 0;
ViewPort.Height = RENDERTARGSIZE;
ViewPort.Width = RENDERTARGSIZE;
ViewPort.MaxZ = 1;
ViewPort.MinZ = 0;
m_pDev->SetViewport(&ViewPort);
m_pDev->Clear(0, NULL, D3DCLEAR_TARGET , D3DCOLOR_ARGB( 0x00, 0x00, 0x00, 0x00), 1.0, 0);
m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pDev->SetRenderState( D3DRS_ALPHATESTENABLE,FALSE);
m_pDev->SetRenderState(D3DRS_WRAP0,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetRenderState(D3DRS_WRAP1,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DOTPRODUCT3);
m_pDev->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pDev->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT); //D3DTA_CURRENT);
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_pDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
m_pDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
m_pDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);
m_pDev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetRenderState(D3DRS_WRAP0, D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetRenderState(D3DRS_WRAP1, D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
//render all the basis functions times all the images
m_pDev->SetStreamSource( 0, m_pVertices, sizeof(ShaderVertex) );
m_pDev->SetVertexShader(m_dwBasisShader);
for(i = 0;i < 3;i++)
{
m_pDev->SetTexture(0, m_pHorizonTextures[i]);
m_pDev->SetTexture(1, m_pBasisTextures[i]);
hr = m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_iNumVertices,0,m_iNumTriangles);
}
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
pSurface->Release();
//now we have to render a simple alpha texture to subtract off for the shadow
hr = m_pRenderBuffer2->GetSurfaceLevel(0,&pSurface);
hr = m_pDev->SetRenderTarget(pSurface,NULL);
m_pDev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB( 0x00, 0x00, 0x00, 0x00), 1.0, 0);
m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
m_pDev->SetRenderState( D3DRS_ALPHATESTENABLE,FALSE);
m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
m_pDev->SetStreamSource( 0, m_pVertices, sizeof(ShaderVertex) );
m_pDev->SetVertexShader(m_dwShadowShader);
hr = m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_iNumVertices,0,m_iNumTriangles);
//restore our states
m_pDev->SetRenderTarget(m_pOldRenderTarget,m_pOldStencilZ);
pSurface->Release();
m_pDev->SetViewport(&OldPort);
}
}
m_pDev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0x00, 0x00, 0x00, 0x00), 1.0, 0);
m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetRenderState(D3DRS_WRAP0,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetRenderState(D3DRS_WRAP1,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
//important to unset a pixel shader!
m_pDev->SetPixelShader(0);
//diffuse, DOT3 lighting.
if(bBump)
{
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT);
m_pDev->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1);
m_pDev->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pDev->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pDev->SetTexture(1,m_pColorTexture);
m_pDev->SetTexture(0,m_pNormalMap);
}
else
{
//no lighting, just base color texture
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
m_pDev->SetTexture(0,m_pColorTexture);
}
m_pDev->SetStreamSource( 0, m_pVertices, sizeof(ShaderVertex) );
m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);
m_pDev->SetVertexShader(m_dwBumpShader);
hr = m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_iNumVertices,0,m_iNumTriangles);
m_pDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
m_pDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
m_pDev->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_NONE);
//now apply the black mask
if(bShad)
{
//emmulate pixel shaders
//the first two passes (the basis computation and the
//light angle computation) were done before
if(!m_bUsePix)
{
//now, subtract the light angle from the she shadow angle
//if the value is non zero, then the pixel is in shaddow
m_pDev->SetStreamSource(0, m_pShad1,6*sizeof(FLOAT));
m_pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_TEX1);
m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
m_pDev->SetRenderState(D3DRS_WRAP0,0);
m_pDev->SetRenderState(D3DRS_WRAP1,0);
m_pDev->SetRenderState(D3DRS_TEXTUREFACTOR,s_Verts3[0].color);
m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
if(bShow)
m_pDev->SetRenderState(D3DRS_TEXTUREFACTOR,D3DCOLOR_ARGB( 0xff,0xff, 0x00, 0x00 ));
else
m_pDev->SetRenderState(D3DRS_TEXTUREFACTOR,0x80202020);
m_pDev->SetRenderState(D3DRS_TEXTUREFACTOR,0x60606060);
m_pDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pDev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SUBTRACT);
m_pDev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pDev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
m_pDev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TFACTOR);
//use an alpha test - if alpha is non zero,
m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);
m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pDev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL);
m_pDev->SetRenderState(D3DRS_ALPHAREF,0);
m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 0 );
m_pDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);
m_pDev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);
m_pDev->SetTexture(0, m_pRenderBuffer2);
m_pDev->SetTexture(1, m_pRenderBuffer);
m_pDev->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
}
else
{
//use the pixel shader, much faster...
//turn wrapping and blending on all the stages
m_pDev->SetRenderState(D3DRS_WRAP0,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetRenderState(D3DRS_WRAP1,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetRenderState(D3DRS_WRAP2,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetRenderState(D3DRS_WRAP3,D3DWRAPCOORD_0 | D3DWRAPCOORD_1);
m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 3, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 3, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 2, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
m_pDev->SetTextureStageState( 3, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
//bind the textures
m_pDev->SetTexture(0, m_pHorizonTextures[0]);
m_pDev->SetTexture(1, m_pBasisTextures[0]);
m_pDev->SetTexture(2, m_pHorizonTextures[1]);
m_pDev->SetTexture(3, m_pBasisTextures[1]);
//render all the basis functions times all the images
m_pDev->SetStreamSource( 0, m_pVertices, sizeof(ShaderVertex) );
m_pDev->SetVertexShader(m_dwShadowShader);
m_pDev->SetPixelShader(m_dwPixShader);
m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE);
m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCCOLOR);
m_pDev->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);
//run the pixel shader/vertex shader
//these will summ up all the basis maps and then compare at a per
//pixel level with the light angle.
//the output is the (inverse) shadow term
hr = m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_iNumVertices,0,m_iNumTriangles);
}
}
Fail:
return;
}
//set the index and vertex buffer for the object being rendered.
VOID ShadowSet::SetBuffers(LPDIRECT3DINDEXBUFFER8 pIndex,LPDIRECT3DVERTEXBUFFER8 pVertBuffer,
INT iNumFaces,INT iNumVertices)
{
m_pIndexBuffer = pIndex;
pIndex->AddRef();
m_pVertices = pVertBuffer;
pVertBuffer->AddRef();
m_iNumTriangles = iNumFaces;
m_iNumVertices = iNumVertices;
}